﻿using System;
using System.Collections.Generic;
using System.Linq;
using HK.Core.Common;
using HK.Core.Common.Data;
using HK.Core.Common.Protocol.Data;
using HK.Core.Extend;
using HK.Core.Utils;
using HK.Editor.Defines.Protocol.Data;
using HK.Editor.GUIEx.Protocol.TreeView.Data;
using UnityEditor;
using UnityEngine;

namespace HK.Editor.Defines.Data
{
    /// <summary>
    /// 宏定义
    /// </summary>
    [Serializable]
    public class DefineInfo : JsonData<DefineInfo>, IDefineInfo, IEquatable<DefineInfo>
    {

#region Create

        /// <summary>
        /// 创建宏信息
        /// </summary>
        /// <returns>宏信息</returns>
        public static DefineInfo Create() => Create(null);

        /// <summary>
        /// 创建宏信息
        /// </summary>
        /// <param name="iDefine">宏名</param>
        /// <param name="iIOS">iOS</param>
        /// <param name="iAndroid">Android</param>
        /// <param name="iPc">Pc</param>
        /// <param name="iPs4">Ps4</param>
        /// <param name="iPs5">Ps5</param>
        /// <param name="iXboxOne">Xbox One</param>
        /// <returns>宏信息</returns>
        public static DefineInfo Create(
            string iDefine, bool iIOS = false, bool iAndroid = false, 
            bool iPc = false, bool iPs4 = false, bool iPs5 = false, bool iXboxOne = false)
        {
            var define = new DefineInfo(iDefine) { New = true };
	        
            // iOS
            define.SetStatus(PlatformType.IOS, iIOS);

            // Android
            define.SetStatus(PlatformType.Android, iAndroid);
            define.SetStatus(PlatformType.Bilibili, iAndroid);
            define.SetStatus(PlatformType.Huawei, iAndroid);
            define.SetStatus(PlatformType.Tabtap, iAndroid);
	        
            // Ps4
            define.SetStatus(PlatformType.Ps4, iPs4);
	        
            // Ps5
            define.SetStatus(PlatformType.Ps5, iPs5);
	        
            // XboxOne
            define.SetStatus(PlatformType.XboxOne, iXboxOne);
	        
            // Pc
            define.SetStatus(PlatformType.StandaloneWindows, iPc);
            define.SetStatus(PlatformType.StandaloneWindows64, iPc);
	        
            return define;
        }

#endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        public DefineInfo() : this("Root") {}

        /// <summary>
        /// 保护构造函数
        /// </summary>
        protected DefineInfo(string iDefine)
        {
            define = iDefine;
        }

#region TreeBranch

        [SerializeField]
        private int id = -1;

        /// <summary>
        /// Id
        /// </summary>
        public int Id
        {
            get => id; 
            set => id = value;
        }

        /// <summary>
        /// 唯一标识Element的Key
        /// </summary>
        public string Key => $"{Id}_{define}";
        
        /// <summary>
        /// Name
        /// </summary>
        public string Name => define;

        /// <summary>
        /// 深度
        /// </summary>
        public int Depth { get; set; } = 0;

        /// <summary>
        /// 根节点标志位
        /// </summary>
        public bool IsRoot => -1 == Depth;

        /// <summary>
        /// 父节点
        /// </summary>
        public ITreeBranch Parent { get; set; } = null;

        /// <summary>
        /// 子节点列表
        /// </summary>
        public List<ITreeBranch> Children { get; set; } = null;

        /// <summary>
        /// 子节点数量
        /// </summary>
        public int ChildCount => Children?.Count ?? 0;

        /// <summary>
        /// 子节点列表有效标志位
        /// </summary>
        public bool ValidChildren => null != Children;

        /// <summary>
        /// 是否拥有子节点标志位
        /// </summary>
        public bool HasChildren => ValidChildren && 0 < Children.Count;

#endregion

        /// <summary>
        /// 是否勾选
        /// </summary>
        public bool Selected { get; set; } = false;
        
        [SerializeField]
        private string define = null;
        /// <summary>
        /// 宏
        /// </summary>
        public string Define
        {
            get => define;
            set => define = value;
        }

        [SerializeField]
        private string tips = null;
        /// <summary>
        /// Tips
        /// </summary>
        public string Tips 
        {
            get => tips;
            set => tips = value;
        }

        [SerializeField]
        private int dValue = (int)PlatformType.None;
        /// <summary>
        /// 值
        /// </summary>
        public int Value 
        {
            get => dValue;
            set => dValue = value;
        }
        
        /// <summary>
        /// iOS
        /// </summary>
        public bool iOS
        {
            get => UtilsBytes.CheckBytes(dValue, (int)PlatformType.IOS);
            set => dValue = UtilsBytes.SetBytes(dValue, (int)PlatformType.IOS, value);
        }

        /// <summary>
        /// Android
        /// </summary>
        public bool Android
        {
            get =>
                UtilsBytes.CheckBytes(dValue, (int)PlatformType.Android) ||
                UtilsBytes.CheckBytes(dValue, (int)PlatformType.Huawei) ||
                UtilsBytes.CheckBytes(dValue, (int)PlatformType.Bilibili) ||
                UtilsBytes.CheckBytes(dValue, (int)PlatformType.Tabtap);
            set
            {
                dValue = UtilsBytes.SetBytes(dValue, (int)PlatformType.Android, value);
                dValue = UtilsBytes.SetBytes(dValue, (int)PlatformType.Huawei, value);
                dValue = UtilsBytes.SetBytes(dValue, (int)PlatformType.Bilibili, value);
                dValue = UtilsBytes.SetBytes(dValue, (int)PlatformType.Tabtap, value);
            }
        }

        /// <summary>
        /// Ps4
        /// </summary>
        public bool Ps4
        {
            get => UtilsBytes.CheckBytes(dValue, (int)PlatformType.Ps4);
            set => dValue = UtilsBytes.SetBytes(dValue, (int)PlatformType.Ps4, value);
        }

        /// <summary>
        /// Ps5
        /// </summary>
        public bool Ps5
        {
            get => UtilsBytes.CheckBytes(dValue, (int)PlatformType.Ps5);
            set => dValue = UtilsBytes.SetBytes(dValue, (int)PlatformType.Ps5, value);
        }

        /// <summary>
        /// XboxOne
        /// </summary>
        public bool XboxOne
        {
            get => UtilsBytes.CheckBytes(dValue, (int)PlatformType.XboxOne);
            set => dValue = UtilsBytes.SetBytes(dValue, (int)PlatformType.XboxOne, value);
        }

        /// <summary>
        /// Pc
        /// </summary>
        public bool Pc
        {
            get =>
                UtilsBytes.CheckBytes(dValue, (int)PlatformType.StandaloneWindows) ||
                UtilsBytes.CheckBytes(dValue, (int)PlatformType.StandaloneWindows64);
            set => dValue = UtilsBytes.SetBytes(dValue, (int)PlatformType.StandaloneWindows, value);
        }

        /// <summary>
        /// 详细信息
        /// </summary>
        public string Detail => $"Define:{Define} IOS:{iOS} Android:{Android} Pc:{Pc} Ps4:{Ps4} Ps5:{Ps5} XboxOne:{XboxOne} Pc:{Pc}";

        /// <summary>
        /// 新宏标志位
        /// </summary>
        public bool New { get; private set; } = false;

        /// <summary>
        /// 有效标志位
        /// </summary>
        public override bool Valid => -1 != id && !string.IsNullOrEmpty(define);
        
#region Equals

        /// <summary>
        /// 比较
        /// </summary>
        /// <param name="iDefine">宏定义</param>
        /// <returns>true:相同; false:不相同;</returns>
        public bool Equals(DefineInfo iDefine)
        {
            if (null == iDefine || !iDefine.Valid) return false;

            if (UtilsString.Diff(define, iDefine.Define)) return false;
            if (UtilsString.Diff(tips, iDefine.Tips)) return false;
            if (dValue != iDefine.Value) return false;
            return true;
        }

#endregion
        
        /// <summary>
        /// 设定宏状态
        /// </summary>
        /// <param name="iPlatform">Platform</param>
        /// <param name="iOnOrOff">On/Off</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public bool SetStatus(PlatformType iPlatform, bool iOnOrOff)
        {
            var lastValue = dValue;
            dValue = UtilsBytes.SetBytes(dValue, (int) iPlatform, iOnOrOff);
            return lastValue != dValue;
        }

        /// <summary>
        /// 克隆
        /// </summary>
        /// <returns>宏定义</returns>
        public IDefineInfo Clone()
        {
            var newDefine = Create(Define, iOS, Android, Pc, Ps4, Ps5, XboxOne);
            newDefine.Id = Id;
            newDefine.Tips = Tips;
            return newDefine;
        }

        /// <summary>
        /// 应用数据
        /// </summary>
        /// <param name="iData">数据</param>
        /// <param name="iImport">导入标志位(true:从相应的*.json文件导入; false:反之;)</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public override bool ApplyData(IJsonData iData, bool iImport = false)
        {
            if (null == iData || !iData.Valid) return false;

            var dirty = base.ApplyData(iData, iImport);
            if (dirty && !iImport)
            {
                Dirty = true;
            }

            if (iData is IDefineInfo info)
            {
                define = UpdateValue(define, info.Define, iImport);
                tips = UpdateValue(tips, info.Tips, iImport);
                dValue = UpdateValue(dValue, info.Value, iImport);
            }

            return Dirty;
        }

        /// <summary>
        /// 清空
        /// </summary>
        public override void Clear()
        {
            base.Clear();
            
            define = null;
            tips = null;
            dValue = (int)PlatformType.None;
        }
    }
    
    /// <summary>
    /// 宏定义列表
    /// </summary>
    [Serializable]
    public class DefinesData : ListJsonData<DefinesData, DefineInfo>, IDefinesData<DefinesData, DefineInfo>
    {
        /// <summary>
        /// 负载Tag
        /// </summary>
        public string PayloadTag => GetType().Name;

        /// <summary>
        /// 宏定义列表
        /// </summary>
        public List<DefineInfo> Defines => list;
        
        /// <summary>
        /// 重置宏设定
        /// </summary>
        /// <param name="iDefines">宏列表详细信息(以分号分割。如:AAA;BBB;CCC)</param>
        /// <param name="iTargetGroup">目标平台类型</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public bool ResetDefines(string iDefines, BuildTargetGroup iTargetGroup)
        {
            if(string.IsNullOrEmpty(iDefines)) return false;
            var definesTmp = iDefines.Split(';');
            if(0 >= definesTmp.Length) return false;
			
            // 重置所有宏 -> Off
            ResetAllDefines(iTargetGroup, false);
			
            // 追加宏
            return AddDefines(definesTmp, iTargetGroup, true);
        }

        /// <summary>
        /// 设定宏
        /// </summary>
        /// <param name="iDefine">宏</param>
        /// <param name="iTargetGroup">目标平台类型</param>
        /// <param name="iOnOrOff">On/Off</param>
        /// <returns>true:设定成功; false:设定失败;</returns>
        public bool SetDefine(IDefineInfo iDefine, BuildTargetGroup iTargetGroup, bool iOnOrOff)
        {
            if(null == iDefine || !iDefine.Valid) return false;

            var dirty = false;
            switch (iTargetGroup)
            {
                case BuildTargetGroup.iOS:
                {
                    if (iDefine.SetStatus(PlatformType.IOS, iOnOrOff))
                    {
                        dirty = true;
                    }
                }
                    break;
                case BuildTargetGroup.Android:
                {
                    if (iDefine.SetStatus(PlatformType.Android, iOnOrOff))
                    {
                        dirty = true;
                    }
                    if (iDefine.SetStatus(PlatformType.Huawei, iOnOrOff))
                    {
                        if (!dirty)
                        {
                            dirty = true;
                        }
                    }

                    if (iDefine.SetStatus(PlatformType.Bilibili, iOnOrOff))
                    {
                        if (!dirty)
                        {
                            dirty = true;
                        }
                    }

                    if (iDefine.SetStatus(PlatformType.Tabtap, iOnOrOff))
                    {
                        if (!dirty)
                        {
                            dirty = true;
                        }
                    }
                }
                    break;
                case BuildTargetGroup.PS4:
                {
                    if (iDefine.SetStatus(PlatformType.Ps4, iOnOrOff))
                    {
                        dirty = true;
                    }
                }
                    break;
                case BuildTargetGroup.PS5:
                {
                    if (iDefine.SetStatus(PlatformType.Ps5, iOnOrOff))
                    {
                        dirty = true;
                    }
                }
                    break;
                case BuildTargetGroup.XboxOne:
                {
                    if (iDefine.SetStatus(PlatformType.XboxOne, iOnOrOff))
                    {
                        dirty = true;
                    }
                }
                    break;
                case BuildTargetGroup.Standalone:
                {
                    if (iDefine.SetStatus(PlatformType.StandaloneWindows, iOnOrOff))
                    {
                        dirty = true;
                    }

                    if (iDefine.SetStatus(PlatformType.StandaloneWindows64, iOnOrOff))
                    {
                        if (!dirty)
                        {
                            dirty = true;
                        }
                    }
                }
                    break;
                default:
                    break;
            }
			
            return dirty;
        }

        /// <summary>
        /// 重置所有的Defines
        /// </summary>
        /// <param name="iTargetGroup">目标平台类型</param>
        /// <param name="iOnOrOff">On/Off</param>
        public void ResetAllDefines(BuildTargetGroup iTargetGroup, bool iOnOrOff)
        {
            var count = Defines.Count;
            for (var idx = 0; idx < count; ++idx)
            {
                var define = Defines[idx];
                if(null == define || !define.Valid) continue;

                // 设定宏
                SetDefine(define, iTargetGroup, iOnOrOff);
            }
        }

        /// <summary>
        /// 存在校验
        /// </summary>
        /// <param name="iDefine">宏名</param>
        /// <param name="oDefine">宏信息</param>
        /// <returns>true:存在; false:不存在;</returns>
        private bool Exist(string iDefine, out DefineInfo oDefine)
        {
            oDefine = null;
            if (string.IsNullOrEmpty(iDefine) || 0 >= Defines.Count) return false;

            var count = Defines.Count;
            for (var idx = 0; idx < count; ++idx)
            {
                var loop = Defines[idx];
                if(null == loop || !loop.Valid || !iDefine.Equals(loop.Define)) continue;

                oDefine = loop;
                break;
            }

            return null != oDefine && oDefine.Valid;
        }

        /// <summary>
        /// 存在校验
        /// </summary>
        /// <param name="iId">宏Id</param>
        /// <param name="oDefine">宏信息</param>
        /// <returns>true:存在; false:不存在;</returns>
        private bool Exist(int iId, out DefineInfo oDefine)
        {
            oDefine = null;
            if (0 >= iId || 0 >= Defines.Count) return false;

            var count = Defines.Count;
            for (var idx = 0; idx < count; ++idx)
            {
                var loop = Defines[idx];
                if(null == loop || !loop.Valid || iId != loop.Id) continue;

                oDefine = loop;
                break;
            }

            return null != oDefine && oDefine.Valid;
        }

        /// <summary>
        /// 生成宏Id
        /// </summary>
        /// <returns>宏Id</returns>
        private int GenerateId() => Count + 1;
        
        /// <summary>
        /// 追加宏.
        /// </summary>
        /// <param name="iDefine">宏定义列表</param>
        /// <returns>true:OK; false:NG;</returns>
        public bool AddDefine(IDefineInfo iDefine)
        {
            if(null == iDefine) return false;
            
            if (Exist(iDefine.Define, out var oDefine))
            {
                this.Error("AddDefine():The macro is exist!(Define:{0})", iDefine.Define);
                return false;
            }

            var newDefine = DefineInfo.Create(iDefine.Define, iDefine.iOS, iDefine.Android, 
                iDefine.Pc, iDefine.Ps4, iDefine.Ps5, iDefine.XboxOne);
            newDefine.Id = GenerateId();
            newDefine.Tips = iDefine.Tips;
            Defines.Add (newDefine);
            return true;
        }

        /// <summary>
        /// 保存宏
        /// </summary>
        /// <param name="iDefine">宏定义列表</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public bool SaveDefine(IDefineInfo iDefine)
        {
            if(null == iDefine || !iDefine.Valid) return false;
            
            if (!Exist(iDefine.Id, out var oDefine))
            {
                return false;
            }

            if (null == oDefine || !oDefine.Valid) return false;
            return oDefine.ApplyData(iDefine);
        }

        /// <summary>
        /// 删除宏
        /// </summary>
        /// <param name="iDefine">宏定义列表</param>
        /// <returns>true:OK; false:NG;</returns>
        public bool DelDefine(IDefineInfo iDefine)
        {
            if(null == iDefine || !iDefine.Valid) return false;
            
            if (!Exist(iDefine.Id, out var oDefine))
            {
                return false;
            }

            return list.Remove(oDefine);
        }

        /// <summary>
        /// 追加宏.
        /// </summary>
        /// <param name="iDefines">宏定义列表</param>
        /// <param name="iTargetGroup">目标平台类型</param>
        /// <param name="iOnOrOff">On Or Off</param>
        /// <returns>true:有变更; false:无变更;</returns>
        public bool AddDefines(string[] iDefines, BuildTargetGroup iTargetGroup, bool iOnOrOff)
        {
            if (null == iDefines || 0 >= iDefines.Length || null == Defines) 
            {
                return false;
            }

            var dirty = false;
            var len = iDefines.Length;
            for (var idx = 0; idx < len; ++idx)
            {
                var define = iDefines[idx];
                if(string.IsNullOrEmpty(define)) continue;

                // 存在校验
                if (Exist(define, out var oDefine))
                {
                    // 设定宏
                    if (SetDefine(oDefine, iTargetGroup, iOnOrOff))
                    {
                        if (!dirty)
                        {
                            dirty = true;
                        }
                    }
                    continue;
                }
                
                // 追加宏定义设定
                var newDefine = DefineInfo.Create(define, BuildTargetGroup.iOS == iTargetGroup, 
                    BuildTargetGroup.Android == iTargetGroup, BuildTargetGroup.Standalone == iTargetGroup, 
                    BuildTargetGroup.PS4 == iTargetGroup, BuildTargetGroup.PS5 == iTargetGroup, 
                    BuildTargetGroup.XboxOne == iTargetGroup);
                Defines.Add (newDefine);
                if (!dirty)
                {
                    dirty = true;
                }
                this.Info("AddDefine -> {0}", newDefine.Detail);
            }
			
            // 按名字排序
            Defines.Sort((iX,iY) => (string.Compare(iX.Define, iY.Define, StringComparison.Ordinal)));
            
            // 重置所有Id
            var count = Defines.Count;
            for (var idx = 0; idx < count; ++idx)
            {
                var define = Defines[idx];
                define.Id = idx + 1;
            }

            return dirty;
        }

        /// <summary>
        /// Apply
        /// </summary>
        public void Apply()
        {
            // iOS
            var targetDefines = Defines
                .Where (iO => iO.iOS)
                .OrderBy (iO => iO.Define)
                .ToArray ();
            DefinesSetting.AppDefinesToPlatform (targetDefines, BuildTargetGroup.iOS);
			
            // Android
            targetDefines = Defines
                .Where (iO => iO.Android)
                .OrderBy (iO => iO.Define)
                .ToArray ();
            DefinesSetting.AppDefinesToPlatform (targetDefines, BuildTargetGroup.Android);
			
            // Ps4
            targetDefines = Defines
                .Where (iO => iO.Ps4)
                .OrderBy (iO => iO.Define)
                .ToArray ();
            DefinesSetting.AppDefinesToPlatform (targetDefines, BuildTargetGroup.PS4);
			
            // Ps5
            targetDefines = Defines
                .Where (iO => iO.Ps5)
                .OrderBy (iO => iO.Define)
                .ToArray ();
            DefinesSetting.AppDefinesToPlatform (targetDefines, BuildTargetGroup.PS5);
			
            // XboxOne
            targetDefines = Defines
                .Where (iO => iO.XboxOne)
                .OrderBy (iO => iO.Define)
                .ToArray ();
            DefinesSetting.AppDefinesToPlatform (targetDefines, BuildTargetGroup.XboxOne);
			
            // Pc
            targetDefines = Defines
                .Where (iO => iO.Pc)
                .OrderBy (iO => iO.Define)
                .ToArray ();
            DefinesSetting.AppDefinesToPlatform (targetDefines, BuildTargetGroup.Standalone);
        }
        
    }
}
